#!/usr/bin/env bash

ssl_include_path() {
    case "$(uname)" in
	MINGW32*)
	    echo /mingw32/include/openssl;;
	MINGW64*)
	    echo /mingw64/include/openssl;;
	*)
	    echo "${with_openssl:-/usr}/include/openssl"
	    ;;
    esac
}

rpm_version() {
    if type -p rpm >/dev/null 2>&1; then
	rpm -q --qf '%{version}\n' "$1" 2>/dev/null | grep -v 'not installed'
    fi
}

dpkg_version() {
    if type -p dpkg-query >/dev/null 2>&1; then
	dpkg-query --show -f '${Version}\n' "$1" 2>/dev/null | grep -v '^$'
    fi
}

pacman_version() {
    if type -p pacman >/dev/null 2>&1; then
	pacman -Q "$1" 2>/dev/null | sed -n 's/^[^[:blank:]]*[[:blank:]]*//p'
    fi
}

apk_version() {
    if type -p apk >/dev/null 2>&1; then
	apk info -d "$1" | sed -n "s/^$1-\(.*\)-r[0-9]* description:/\1/p"
    fi
}

freebsd_pkg_version() {
    local pkg ver

    for pkg in "$@"; do
	ver=$(pkg info "$pkg" 2>/dev/null |
		     sed -n 's/^Version[[:blank:]]*:[[:blank:]]*//p') &&
	    [ -n "$ver" ] && echo "$ver" && return
    done
    return 1
}

# Given the name of a compiler executable ($1), derive the compiler type (gcc,
# clang, xlc, ...).
compiler_type() {
    "$1" -v 2>&1 |
        sed -n 's/^gcc version .*/gcc/p;s/^clang version .*/clang/p;s/.*xlc.*IBM.*xlc.*/xlc/p'
}

scriptdir=$(cd "$(dirname "$0")" && pwd)
branch_name="$1"
shift

case "$MODE" in
    Android)
	;;
    *)
	libatmver="$(rpm_version linux-atm-devel;
		     dpkg_version libatm1-dev)"
	echo "libatmver=$libatmver"

	libmysqlver="$(rpm_version libmariadb-devel;
	      for p in libmariadbclient-dev libmariadb-client-lgpl-dev; do
	        dpkg_version "$p";
              done;
              pacman_version mingw-w64-x86_64-libmariadbclient)"
	echo "libmysqlver=$libmysqlver"

	libsensorsver="$(rpm_version libsensors4-devel;
		 dpkg_version libsensors4-dev)"
	echo "libsensorsver=$libsensorsver"

	if echo "$*" | grep -q wolfssl; then
	    have_ssl=true
	elif ! echo "$*" | grep -Eq 'with-openssl=(no|internal)|without-openssl'; then
	    have_ssl=true
	fi
	echo "have_ssl=$have_ssl"

	case "$(uname)" in
	    FreeBSD*)
		libssh2ver="$(freebsd_pkg_version libssh2 2>/dev/null)";;
	    Linux*)
		libssh2ver="$(for p in openssh-devel libssh2-devel libssh-devel
			do
			    rpm_version "$p";
			done |
			head -n1;
			for p in libopenssh2 libssh2-1-dev libssh-dev; do
			    dpkg_version "$p";
			done;
			pacman_version mingw-w64-x86_64-libssh2)"
		;;
	esac
	echo "libssh2ver=$libssh2ver"

	case "$(uname)" in
	    FreeBSD*)
		perldevver="$(freebsd_pkg_version perl5 2>/dev/null)";;
	    Linux*)
		perldevver="$(rpm_version perl;
			      dpkg_version libperl-dev;
			      pacman_version mingw-w64-x86_64-perl)"
		;;
	esac
	echo "perldevver=$perldevver"
	# Set the perlcc variable.
	eval "perl$(perl -V:cc)"
	perlcc=$(compiler_type "$perlcc")
	echo "perlcc=$perlcc"
	;;
esac

options=()
options+=(--enable-developer)
options+=(--enable-ipv6)
options+=("--prefix=/usr/local/net-snmp-${branch_name}")
options+=("--with-cflags=$CFLAGS")
options+=(--with-defaults)
transports=()
# Mib names can be found as follows:
# (cd agent/mibgroup &&
# git grep -lE 'void[[:blank:]]*init_.*\(void\)|config_require\(' |
#  sed -n 's/\.h$//p')
mibs=()
mibs+=(agent/extend)
case "$MODE" in
    read-only)
	;;
    Android)
	options+=(
	    --disable-embedded-perl
	    --host=aarch64-linux-android33
	    --with-openssl=internal
	    --with-out-mib-modules="if-mib default_modules"
	    --without-perl-modules
	    --without-python-modules
	)
        ;;
    *)
        mibs+=(examples/data_set)
        mibs+=(examples/delayed_instance)
        mibs+=(examples/example)
        mibs+=(examples/notification)
        mibs+=(examples/scalar_int)
        mibs+=(examples/ucdDemoPublic)
        mibs+=(examples/watched)
        mibs+=(smux)
        ;;
esac

case "$(uname):${MODE}" in
  *:Android*)
      ;;
  Linux*)
      options+=(--enable-new-features)
      case "$MODE" in
          mini*|read-only)
              ;;
          *)
              mibs+=(deliver/deliverByNotify)
              mibs+=(disman/event)
              mibs+=(disman/expression)
              mibs+=(disman/mteEventNotificationTable)
              mibs+=(disman/mteEventTable)
              mibs+=(disman/mteObjectsTable)
              mibs+=(disman/mteTriggerBooleanTable)
              mibs+=(disman/mteTriggerDeltaTable)
              mibs+=(disman/mteTriggerExistenceTable)
              mibs+=(disman/mteTriggerTable)
              mibs+=(disman/mteTriggerThresholdTable)
              mibs+=(disman/nslookup-mib)
              mibs+=(disman/ping-mib)
              mibs+=(disman/schedule)
              mibs+=(disman/traceroute-mib)
              mibs+=(etherlike-mib)
              mibs+=(examples/netSnmpHostsTable)
              mibs+=(hardware/cpu)
              mibs+=(hardware/fsys)
              mibs+=(hardware/memory)
              mibs+=(host)
              mibs+=(ip-forward-mib)
              mibs+=(ip-mib/inetNetToMediaTable)
              mibs+=(ip-mib/ipDefaultRouterTable)
              mibs+=(ip-mib/ipv4InterfaceTable)
              mibs+=(ip-mib/ipv6InterfaceTable)
              mibs+=(ip-mib/ipv6ScopeZoneIndexTable)
              mibs+=(mibII/mta_sendmail)
              mibs+=(misc/ipfwacc)
              mibs+=(sctp-mib)
              mibs+=(snmp-notification-mib)
              mibs+=(tcp-mib)
              mibs+=(testhandler)
              mibs+=(tunnel)
              mibs+=(ucd-snmp/diskio)
	      if [ -n "$libsensorsver" ]; then
		  mibs+=(hardware/sensors)
		  mibs+=(ucd-snmp/lmsensorsMib)
	      fi
              mibs+=(ucd-snmp/extensible)
              mibs+=(udp-mib)
	      mibs+=(rmon-mib)
              ;;
      esac
      if [ -n "$libmysqlver" ]; then
	  options+=(--with-mysql)
      fi
      if [ -n "$perldevver" ] && [ "$perlcc" = "$(compiler_type "${CC:-cc}")" ];
      then
	  options+=(--with-perl-modules)
      else
	  options+=(--disable-embedded-perl --without-perl-modules)
      fi
      if [ -n "$libatmver" ]; then
	  transports+=(AAL5PVC)
      fi
      if [ -e /usr/include/netipx/ipx.h ]; then
	  transports+=(IPX)
      fi
      transports+=(STD)
      transports+=(UDPshared)
      options+=("--with-default-snmp-version=2")
      options+=("--with-systemd")
      # Disabled modules because troublesome: Rmon ipfwchains/ipfwchains ucd-snmp/lmSensors
    ;;
  darwin*|Darwin*)
      case "$MODE" in
          mini*|read-only)
              ;;
          *)
              mibs+=(disman/nslookup-mib)
              mibs+=(host)
              mibs+=(if-mib)
              mibs+=(mibII/mta_sendmail)
              mibs+=(misc/ipfwacc)
              mibs+=(snmp-notification-mib)
              mibs+=(tcp-mib)
              mibs+=(ucd-snmp/diskio)
              mibs+=(ucd-snmp/extensible)
              mibs+=(udp-mib)
              mibs+=(Rmon)
              ;;
      esac
      options+=("--with-openssl=$(brew --prefix openssl)")
    ;;
  FreeBSD*)
      case "$MODE" in
          mini*|read-only)
              ;;
          *)
              mibs+=(disman/nslookup-mib)
              mibs+=(host)
              mibs+=(if-mib)
              mibs+=(mibII/mta_sendmail)
              mibs+=(misc/ipfwacc)
              mibs+=(sctp-mib)
              mibs+=(snmp-notification-mib)
              mibs+=(tcp-mib)
              mibs+=(ucd-snmp/diskio)
              mibs+=(ucd-snmp/extensible)
              mibs+=(udp-mib)
              mibs+=(Rmon)
              ;;
      esac
      options+=(--disable-embedded-perl --without-perl-modules)
    ;;
  CYGWIN*)
      export ENV_SEPARATOR=":"
      mibs+=(ucd-snmp/extensible)
      mibs+=(winExtDLL)
      options+=(--disable-embedded-perl --without-perl-modules)
    ;;
  MINGW*)
      options+=(--disable-embedded-perl)
      mibs+=(host)
      mibs+=(snmp-notification-mib)
      mibs+=(ucd-snmp/dlmod)
      mibs+=(ucd-snmp/extensible)
      mibs+=(winExtDLL)
      options+=(--without-perl-modules)
    ;;
  MSYS*)
      options+=(--disable-embedded-perl)
      mibs+=(host)
      mibs+=(snmp-notification-mib)
      mibs+=(ucd-snmp/dlmod)
      mibs+=(ucd-snmp/extensible)
      mibs+=(winExtDLL)
      options+=(--without-perl-modules)
      # The config.guess script in the Net-SNMP source tree is too old to
      # recognize the MSYS2 environment. Hence the explicit --build=... option.
      # See also
      # http://git.savannah.gnu.org/cgit/automake.git/tree/lib/config.guess.
      options+=("--build=x86_64-pc-mingw32")
    ;;
  *)
    echo "Unknown OS $(uname)."
    ;;
esac

with_openssl=""
case "$MODE" in
    wolfssl)
	with_openssl=wolfssl
	wolfssl_dir=$(dirname "${scriptdir}")/wolfssl-inst
	options+=(--with-wolfssl="${wolfssl_dir}")
	ssl_include_path=${wolfssl_dir}/include/wolfssl/openssl
	;;
    *)
	with_openssl=""
	for o in "${options[@]}"; do
	    if [ "${o#--with-openssl=}" != "$o" ]; then
		with_openssl="${o#--with-openssl=}"
	    fi
	done
	ssl_include_path=$(ssl_include_path)
	;;
esac
echo "ssl_include_path=${ssl_include_path}"
if [ -z "$have_ssl" ]; then
    options+=("--with-openssl=internal")
    with_openssl="internal"
else
    if grep -rq 'BIO_dgram_get_peer(void)\|define BIO_dgram_get_peer' "${ssl_include_path}" 2>/dev/null; then
	transports+=(DTLSUDP TLSTCP)
    else
	echo "BIO_dgram_get_peer() not found:"
	grep -r BIO_dgram_get_peer "${ssl_include_path}"
    fi
    if [ "$MODE" != "read-only" ]; then
	# these MIB modules do not support read-only
	if [ -e "${ssl_include_path}/dh.h" ]; then
	    mibs+=(snmp-usm-dh-objects-mib)
	fi
	if [ -e "${ssl_include_path}/ssl.h" ] &&
               [ "${ssl_include_path%/wolfssl/openssl}" = "${ssl_include_path}" ]
	then
	    mibs+=(tlstm-mib)
	fi
	mibs+=(tsm-mib)
    fi
fi
if [ "$with_openssl" != "internal" ] &&
       [ -e "${ssl_include_path}/aes.h" ] &&
       [ -e "${ssl_include_path}/evp.h" ] &&
       grep -qw EVP_aes_256_cfb "${ssl_include_path}/evp.h"; then
    options+=(--enable-blumenthal-aes)
fi
security_modules=(usm tsm)
if [ -e /usr/include/krb5.h ]; then
    security_modules+=(ksm)
fi
case "$(uname):${MODE}" in
    *:Android*)
	;;
    MSYS*|MINGW*)
	# Do not enable Python support on MinGW32 nor for the MSYS build
	# environment because the Python interpreter has been built on these
	# environments with Visual C++. That compiler is incompatible with gcc.
        ;;
    Darwin*)
	case "$(uname -r)" in
	    11.*|12.*)
		if python3 -c 'import setuptools' 1>/dev/null 2>&1; then
		    options+=(--with-python-modules)
		fi
		;;
	    *)
		;;
	esac
	;;
    *)
	# To do: fix the build of the Python modules when using WolfSSL.
	if python3 -c 'import setuptools' 1>/dev/null 2>&1 &&
	       [ "$MODE" != "wolfssl" ]; then
	    options+=(--with-python-modules)
	fi
    esac

case "$MODE" in
    disable-set)
        options+=(--disable-set-support);;
    mini)
        options+=(--enable-mini-agent);;
    minimalist)
        options+=(--enable-minimalist);;
    read-only)
        options+=(--enable-read-only);;
    regular|wolfssl|Android|"")
        ;;
    *)
        echo "Error: unknown build type $MODE"
        exit 1;;
esac

[ "${libssh2ver#2}" != "${libssh2ver}" ] && transports+=(SSH)
set -x
./configure "${options[@]}" --with-transports="${transports[*]}" \
            --with-security-modules="${security_modules[*]}"	 \
	    --with-mib-modules="${mibs[*]}" \
	    CFLAGS="$CFLAGS" CPPFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" "$@"
